package library.common.view.dialog.base;

import android.app.Dialog;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.FragmentManager;
import android.support.v7.app.AppCompatDialogFragment;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;

/**
 * @author Created by qiang.hou on 2018/4/20.
 * @version 1.0
 */
public abstract class BaseDialogFragmentV7<T> extends AppCompatDialogFragment {
    private String TAG = "BaseDialogFragment";

    public void setTAG(String TAG) {
        this.TAG = TAG;
    }

    /**
     * common params
     */
    private CommonParams dialogParams = new CommonParams();

    public CommonParams getCommonParams() {
        return dialogParams;
    }

    public void setCommonParams(CommonParams dialogParams) {
        this.dialogParams = dialogParams;
    }

    /**
     * if the fragment initiated (for lazy loading data)
     */
    protected boolean isViewInitiated;

    /**
     * if the fragment data loaded (for lazy loading data)
     */
    protected boolean isDataLoaded = false;

    /**
     * 系统默认onCreateDialog方法返回一个Dialog对象,对其并不做处理
     *
     * @param savedInstanceState Bundle
     * @return dialog
     */
    @NonNull
    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        Dialog dialog = returnDialog();
        return null != dialog ? dialog : super.onCreateDialog(savedInstanceState);
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View mRootView = null;
        if (returnLayoutId() > 0) {
            mRootView = inflater.inflate(returnLayoutId(), container, false);
        }
        if (returnDialogView() != null) {
            mRootView = returnDialogView();
        }
        if (null != mRootView) {
            /*
             * 缓存的view需要判断是否已经被加过parent，如果有parent需要从parent删除，
             * 要不然会发生这个view已经有parent的错误。
             */
            ViewGroup parent = (ViewGroup) mRootView.getParent();
            if (parent != null) {
                parent.removeView(mRootView);
            }
            onBindViewData(mRootView);
        }
        return mRootView;
    }

    /**
     * call after onCreateView
     *
     * @param view               mRootView
     * @param savedInstanceState Bundle
     */
    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        Dialog dialog = getDialog();
        // dialog title
        if (dialogParams.isHasDialogTitle) {
            dialog.setTitle(dialogParams.title);
        } else {
            dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
        }
        dialog.setCanceledOnTouchOutside(dialogParams.isCancelableOutside);
        setCancelable(isCancelable());
    }

    @Override
    public void onStart() {
        super.onStart();
        Window dialogWindow = getDialog().getWindow();
        if (dialogWindow != null) {
            // set background TRANSPARENT
            dialogWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
            // padding
            dialogWindow.getDecorView().setPadding(
                    dialogParams.paddingLeft >= 0 ? dialogParams.paddingLeft : 0,
                    dialogParams.paddingTop >= 0 ? dialogParams.paddingTop : 0,
                    dialogParams.paddingRight >= 0 ? dialogParams.paddingRight : 0,
                    dialogParams.paddingBottom >= 0 ? dialogParams.paddingBottom : 0);
            /*
             * layout params
             */
            WindowManager.LayoutParams layoutParams = dialogWindow.getAttributes();
            // width and height
            layoutParams.width = dialogParams.width > 0 ?
                    dialogParams.width :
                    (int) (dialogParams.widthScreenPercent <= 0 || dialogParams.widthScreenPercent > 1 ?
                            WindowManager.LayoutParams.WRAP_CONTENT :
                            (getContext() == null ? WindowManager.LayoutParams.WRAP_CONTENT :
                                    getContext().getResources().getDisplayMetrics().widthPixels * dialogParams.widthScreenPercent));
            layoutParams.height = dialogParams.height > 0 ? dialogParams.height : WindowManager.LayoutParams.WRAP_CONTENT;
            // dim
            layoutParams.dimAmount = dialogParams.dimAmount;
            // gravity
            switch (dialogParams.gravity) {
                case Gravity.TOP:
                case Gravity.BOTTOM:
                case Gravity.LEFT:
                case Gravity.RIGHT:
                case Gravity.START:
                case Gravity.END:
                case Gravity.CENTER:
                    layoutParams.gravity = dialogParams.gravity;
                    break;
                default:
                    // default
                    layoutParams.gravity = Gravity.CENTER;
                    break;
            }
            dialogWindow.setAttributes(layoutParams);
        }
    }

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        /*
         *  (for lazy loading data)
         */
        isViewInitiated = true;
        prepareRequestData();
    }

    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        /*
         *  (for lazy loading data)
         */
        prepareRequestData();
    }

    /**
     * prepare to get data (for lazy loading data)
     */
    public void prepareRequestData() {
        // set param true: force update data when fragment visible
        prepareRequestData(false);
    }

    /**
     * prepare to get data (for lazy loading data)
     *
     * @param forceUpdate true: force update data when fragment visible
     */
    public void prepareRequestData(boolean forceUpdate) {
        if (getUserVisibleHint() && isViewInitiated && (!isDataLoaded || forceUpdate)) {
            initProcess();
            isDataLoaded = true;
        }
    }

    private String getFragmentTag() {
        return TAG;
    }

    /**
     * open api for user to show dialog
     *
     * @param fragmentManager FragmentManager
     */
    public void show(FragmentManager fragmentManager) {
        show(fragmentManager, getFragmentTag());
    }

    @Override
    public void dismiss() {
        super.dismiss();
        if (null != dialogParams.dismissListener) {
            dialogParams.dismissListener.onDismiss(setResult());
        }
    }

    /**
     * call back when dialog dismiss
     *
     * @return T
     */
    protected abstract T setResult();

    /**
     * @return dialog
     */
    protected abstract Dialog returnDialog();

    /**
     * Init data and process
     */
    protected abstract void initProcess();

    /**
     * get layout id
     *
     * @return layout resource id
     */
    protected abstract int returnLayoutId();

    /**
     * get dialog view(same as returnLayoutId(),but has higher priority)
     *
     * @return View
     */
    protected abstract View returnDialogView();

    /**
     * for user to refresh data to ui
     *
     * @param view mRootView
     */
    protected abstract void onBindViewData(View view);

    /**
     *
     */
    public abstract static class Builder<T extends BaseDialogFragmentV7> {

        /**
         * common params
         */
        private CommonParams dialogParams;

        public Builder() {
            dialogParams = new CommonParams();
        }

        public Builder width(int width) {
            dialogParams.width = width;
            return this;
        }

        public Builder widthScreenPercent(float percent) {
            dialogParams.widthScreenPercent = percent;
            return this;
        }

        public Builder height(int height) {
            dialogParams.height = height;
            return this;
        }

        public Builder gravity(int gravity) {
            dialogParams.gravity = gravity;
            return this;
        }

        public Builder dimAmount(int dimAmount) {
            dialogParams.dimAmount = dimAmount;
            return this;
        }

        public Builder padding(int left, int top, int right, int bottom) {
            dialogParams.paddingLeft = left;
            dialogParams.paddingTop = top;
            dialogParams.paddingRight = right;
            dialogParams.paddingBottom = bottom;
            return this;
        }

        public Builder hasTitle(boolean hasTitle) {
            dialogParams.isHasDialogTitle = hasTitle;
            return this;
        }

        public Builder title(String title) {
            dialogParams.title = title;
            return this;
        }

        public Builder isCancelableOutside(boolean isCancelableOutside) {
            dialogParams.isCancelableOutside = isCancelableOutside;
            return this;
        }

        public Builder setOnDismissListener(CommonParams.OnDismissListener listener) {
            dialogParams.dismissListener = listener;
            return this;
        }

        public T create() {
            T dialog = createDialogFragment();
            dialog.setCommonParams(dialogParams);
            return dialog;
        }

        protected abstract T createDialogFragment();
    }
}
